/*
 * 文件名：main.cpp
 * 功能描述：主程序入口和系统初始化
 */
#include <Arduino.h>
#include "config.h"
#include "bsp_ble.h"
#include "bsp_motor.h"
#include "sd_server.h"  // 添加SD卡库
#include "bsp_sdcard.h" // 添加SD卡库
#include "endstop.h"
#include "hall_id.h"
#include "ElectromagnetControl.h"
#include "esp_task_wdt.h"
//#include "button.h"
#include "BatteryMonitor.h"
#include "LEDControl.h"
#include <esp_gatt_common_api.h>
#include "buzzer.h"
#include "Voice_module.h"
#include "OTAUpdate.h"
#include "serial_screen.h"
#include <WiFi.h>
#include <AsyncTCP.h>
#include <ESPAsyncWebServer.h>
#include <ElegantOTA.h>
#include "Display_ST7789.h"
#include "LVGL_Driver.h"
#include <screen.h>
#include "at_command.h"
#include "power_management.h"
#include <esp_system.h>
#include <Preferences.h> // 添加Preferences库
/*
  添加event.h,encooder.h,button.h三个头文件
*/
#include "button.h"
#include "event.h"
#include "encoder.h"
//添加结束
//////////////////////////////////////////////////////////////
extern bool serial_enable_g;

// ====================== 添加：重启历史记录系统 ======================
#define REBOOT_HISTORY_NAMESPACE "reboot_history"
#define REASON_KEY "reason_" // 键名前缀
#define COUNT_KEY "count"
#define INDEX_KEY "index"

Preferences reboot_history;

// 错误原因枚举
enum RebootReason {
  NORMAL = 0,
  WATCHDOG_TIMEOUT,
  EXCEPTION,
  LOW_MEMORY,
  USER_REQUEST,
  POWER_FAILURE,
  WATCHDOUT_TIMEOUT,
  ESP_TASK_DOG,
  ESP_INR_DOG,
  UNKNOWN
};

// 保存重启信息到NVS
void saveRebootInfo(RebootReason reason) {
  reboot_history.begin(REBOOT_HISTORY_NAMESPACE, false);
  
  // 获取当前计数和索引
  uint8_t count = reboot_history.getUChar(COUNT_KEY, 0);
  uint8_t index = reboot_history.getUChar(INDEX_KEY, 0);
  
  // 创建键名（使用char数组）
  char key[15]; // 足够存放 "reason_0" 到 "reason_9"
  snprintf(key, sizeof(key), "%s%d", REASON_KEY, index);
  
  // 保存重启原因
  reboot_history.putInt(key, static_cast<int>(reason));
  
  // 更新索引和计数
  index = (index + 1) % 10;
  if (count < 10) count++;
  
  reboot_history.putUChar(INDEX_KEY, index);
  reboot_history.putUChar(COUNT_KEY, count);
  
  reboot_history.end();
}

//获取错误类型描述
String getReasonDescription(RebootReason reason) {
  switch (reason) {
    case NORMAL: return "正常重启";
    case WATCHDOG_TIMEOUT: return "看门狗超时";
    case EXCEPTION: return "异常崩溃";
    case LOW_MEMORY: return "内存不足";
    case USER_REQUEST: return "用户请求";
    case POWER_FAILURE: return "电源故障";
    default: return "未知原因";
  }
}

// 自动检测重启原因
RebootReason detectRebootReason() {
  esp_reset_reason_t reset_reason = esp_reset_reason();
  
  switch (reset_reason) {
    case ESP_RST_PANIC:
      return EXCEPTION;
    case ESP_RST_INT_WDT:
      return ESP_INR_DOG;
    case ESP_RST_TASK_WDT:
      return ESP_TASK_DOG;
    case ESP_RST_WDT:
      return WATCHDOUT_TIMEOUT;
    case ESP_RST_BROWNOUT:
      return POWER_FAILURE;
    case ESP_RST_SW:
      // 软件重启可能是用户请求或内存不足
      if (esp_get_free_heap_size() < 5000) { // 内存不足阈值
        return LOW_MEMORY;
      }
      return USER_REQUEST;
    default:
      return UNKNOWN;
  }
}

// 获取并打印重启历史
// 获取并打印重启历史
void printRebootHistory() {
  reboot_history.begin(REBOOT_HISTORY_NAMESPACE, true);
  
  // 获取计数和索引
  uint8_t count = reboot_history.getUChar(COUNT_KEY, 0);
  uint8_t index = reboot_history.getUChar(INDEX_KEY, 0);
  
  Serial.println("=== 重启历史记录 ===");
  Serial.printf("总重启次数: %d\n", count);
  
  if (count == 0) {
    Serial.println("无历史记录");
    reboot_history.end();
    return;
  }
  
  // 计算起始位置（最旧的记录）
  uint8_t start = (index + (10 - count)) % 10;
  
  // 打印所有记录
  for (int i = 0; i < count; i++) {
    uint8_t pos = (start + i) % 10;
    
    // 创建键名（使用char数组）
    char key[15];
    snprintf(key, sizeof(key), "%s%d", REASON_KEY, pos);
    
    int reasonCode = reboot_history.getInt(key, UNKNOWN);
    RebootReason reason = static_cast<RebootReason>(reasonCode);
    
    // 修改此行：添加错误宏编号输出
    Serial.printf("重启 #%d: %s (错误码:%d)\n", i+1, getReasonDescription(reason).c_str(), reasonCode);
  }
  
  Serial.println("===================");
  
  reboot_history.end();
}
// ====================== 重启历史记录系统结束 ======================

AsyncWebServer servers4(80);
// 设置AP的IP地址，子网掩码和网关
IPAddress local_ip(192, 168, 149, 1); // 设置AP的IP地址
IPAddress gateway(192, 168, 149, 1);  // 设置AP的网关
IPAddress subnet(255, 255, 255, 0);   // 设置子网掩码

/*
20250926
取消处理LVGL的屏幕任务
*/
// void lvgl_task(void *pvParameter)
// {
//   while (1)
//   {
//     // 每次处理 LVGL 任务
//     lv_task_handler();                   // 这个函数会处理所有的图形更新
//     vTaskDelay(10 / portTICK_PERIOD_MS); // 适当延时，控制任务的频率
//   }
// }

void print_reset_reason() {
  esp_reset_reason_t reason = esp_reset_reason();

  Serial.println("\n*** 重启原因 ***");
  switch (reason) {
    case ESP_RST_UNKNOWN:    Serial.println("原因无法确定"); break;
    case ESP_RST_POWERON:    Serial.println("正常上电开机"); break;
    case ESP_RST_EXT:        Serial.println("外部复位 (NRST 引脚)"); break;
    case ESP_RST_SW:         Serial.println("通过 esp_restart() 软件重启"); break;
    case ESP_RST_PANIC:      Serial.println("系统因异常而重启（软件崩溃、断言失败）"); break;
    case ESP_RST_INT_WDT:    Serial.println("看门狗超时 - 中断看门狗触发（CPU被挂起）"); break;
    case ESP_RST_TASK_WDT:   Serial.println("看门狗超时 - 任务看门狗触发（某个任务长时间运行）"); break;
    case ESP_RST_WDT:        Serial.println("其他看门狗超时（泛指）"); break;
    case ESP_RST_DEEPSLEEP:  Serial.println("从深度睡眠中唤醒"); break;
    case ESP_RST_BROWNOUT:   Serial.println("欠压复位 (Brownout) - 电源电压过低！"); break;
    case ESP_RST_SDIO:       Serial.println("SDIO/USB 模块复位"); break;
    default:                 Serial.printf("未知原因 [%d]\n", reason); break;
  }
  Serial.println("****************");
}

void setup()
{
  // 初始化串口
  Serial.begin(115200);
  Serial.println("\n\n系统启动中...");
  
  // ====================== 添加：自动捕获重启原因 ======================
  // 检测并保存重启原因
  RebootReason reason = detectRebootReason();
  saveRebootInfo(reason);
  
  // 打印重启历史
  printRebootHistory();
  
  // 打印本次启动的原因
  print_reset_reason();
  // ====================== 添加结束 ======================
  
  // 初始化蓝牙（提前到其他外设之前）
  esp_ble_gatt_set_local_mtu(251);
  loadPreferences(); // 先加载preferences，确保sn_g已经初始化

  // 根据SN码决定蓝牙名称
  String bleName = BLE_DEFAULT_NAME;
  if (sn_g.length() == 13) {
    bleName = "CB_" + sn_g;
  }

  // 蓝牙初始化和广播
  ble_g.init(bleName); // 使用确定的名称初始化蓝牙
  delay(100); // 确保蓝牙初始化完成
  BLEDevice::startAdvertising();
  if (print_key) {
    Serial.println("BLE广播已启动");
  }

#if OTA_OR_SCREEN_KEY
  // 设置 AP 的 IP 地址
  if (!WiFi.softAPConfig(local_ip, gateway, subnet)) {
    if (print_key) {
      Serial.println("AP Config Failed!");
    }
  }

  // 同时启用AP和STA模式
  WiFi.mode(WIFI_AP_STA);

  // 启用 AP 模式（创建热点）
  if (WiFi.softAP("Chessbot")) {
    if (serial_enable_g && print_key) {
      Serial.println("AP启动成功");
      Serial.print("AP IP address: ");
      Serial.println(WiFi.softAPIP());
      Serial.print("AP MAC address: ");
      Serial.println(WiFi.softAPmacAddress());
      Serial.print("AP SSID: ");
      Serial.println(WiFi.softAPSSID());
      Serial.print("AP 当前连接设备数: ");
      Serial.println(String(WiFi.softAPgetStationNum()));
    }
  } else if (serial_enable_g && print_key) {
    Serial.println("AP启动失败");
  }

  // 连接WiFi
  if (print_key) {
    Serial.println("正在连接WiFi...");
  }
  WiFi.begin("AAAHOME", "homewifi1234");

  // 等待WiFi连接，最多等待10秒
  int wifiTimeout = 0;
  while (WiFi.status() != WL_CONNECTED && wifiTimeout < 20) {
    delay(500);
    if (print_key) {
      Serial.print(".");
    }
    wifiTimeout++;
  }

  if (WiFi.status() == WL_CONNECTED) {
    if (print_key) {
      Serial.println("WiFi连接成功");
      Serial.print("WiFi IP地址: ");
    }
    IPAddress localIP = WiFi.localIP();
    String ipString = String(localIP[0]) + "." +
                      String(localIP[1]) + "." +
                      String(localIP[2]) + "." +
                      String(localIP[3]);
    if (serial_enable_g && print_key) {
      Serial.println(ipString);
      ip_g = ipString;
      Serial.println("OTA更新方式：");
      Serial.println("1. 通过热点更新：");
      Serial.println("   - 连接到'Chessbot'热点");
      Serial.println("   - 访问 http://192.168.149.1/update");
      Serial.println("2. 通过局域网更新：");
      Serial.println("   - 确保设备在同一WiFi网络下");
      Serial.println("   - 访问 http://" + ipString + "/update");
    }
  } else if (serial_enable_g && print_key) {
    Serial.println("WiFi连接失败");
    Serial.println("OTA更新方式：");
    Serial.println("1. 通过热点更新：");
    Serial.println("   - 连接到'Chessbot'热点");
    Serial.println("   - 访问 http://192.168.149.1/update");
  }

  // 路由设置
  servers4.on("/", HTTP_GET, [](AsyncWebServerRequest *request) {
    request->send(200, "text/plain", "Chessbot OTA!");
  });

  // 配置ElegantOTA
  ElegantOTA.setAutoReboot(true);
  ElegantOTA.onStart([]() {
    if (print_key) {
      Serial.println("OTA更新开始");
    }
  });
  ElegantOTA.onProgress([](unsigned int progress, unsigned int total) {
    if (print_key) {
      Serial.print("OTA进度: ");
      Serial.print((progress * 100) / total);
      Serial.println("%");
    }
  });
  ElegantOTA.onEnd([](bool success) {
    if (success) {
      if (print_key) {
        Serial.println("\nOTA更新成功完成");
      }
    } else {
      if (print_key) {
        Serial.println("\nOTA更新失败");
      }
    }
  });

  Serial.println("Web 服务器启动中...");
  servers4.begin();
  Serial.println("Web 服务器已启动");

  // 尝试初始化ElegantOTA
  bool otaInitialized = false;
  for (int i = 0; i < 3 && !otaInitialized; i++) {
    try {
      ElegantOTA.begin(&servers4, "", "");
      otaInitialized = true;
      Serial.println("ElegantOTA初始化成功");
    } catch (...) {
      Serial.println("ElegantOTA初始化失败，重试中...");
      delay(1000);
    }
  }

  if (!otaInitialized) {
    Serial.println("ElegantOTA初始化失败，请重启设备");
  }
#endif

  speed_set(get_current_speed()); // 设置速度
#if !OTA_OR_SCREEN_KEY

  //screen_init(); // 初始化屏幕
#endif

  Timer_Loop();         // 调用定时器循环函数，处理所有注册的定时任务
  voice_init();         // 初始化语音模块
  buzzer_init();        // 初始化蜂鸣器
  initElectromagnets(); // 初始化电磁铁
  initLEDControl();     // 初始化WS2812
  BatteryStatus_init(); // 初始化电量检测
#if !OTA_OR_SCREEN_KEY
  init_button();        // 初始化按钮 
#endif

  motor_init();    // 初始化电机
  endstop_init();  // 初始化限位开关
  calibrate();     // 校准XY轴
  id_board_init(); // 初始化ID
  at_com_init();   // 初始化串口任务
 /*
    添加编码器和按键相关代码
 */

// 初始化事件系统
  init_events();
// 初始化按钮系统
  init_button();
  xTaskCreate(buttonTask, "Button Task", 2048, NULL, 5, NULL);
// 初始化编码器系统
  init_encoder();
  xTaskCreate(encoderTask, "Encoder Task", 2048, NULL, 5, NULL);
  ////////////////////////////////////////////////////////////
  //代码添加结束


  // 初始化看门狗
  esp_task_wdt_init(50000000, false);
  esp_task_wdt_add(NULL);
 
  
#if LOW_POWER_KEY
  power_init(); // 低功耗模式任务
#endif

#if !OTA_OR_SCREEN_KEY
/*
      20250925
  取消屏幕任务的创建
*/
  // 创建一个专门用于 LVGL 渲染的任务（增加堆栈大小）
  // xTaskCreatePinnedToCore(
  //     lvgl_task,   // 任务函数
  //     "LVGL Task", // 任务名称
  //     16384,       // 任务栈大小增加到16KB
  //     NULL,        // 参数
  //     1,           // 优先级
  //     NULL,        // 任务句柄
  //     0            // 核心编号（0 或 1）
  // );

#endif

  playBuzzer(beepLevel_g, 100, 50); // 关闭蜂鸣器
  playBuzzer(beepLevel_g, 100, 50);
}

void loop()
{
  // 喂狗操作（防止看门狗超时）
  esp_task_wdt_reset();

  // 监控内存状态
  uint32_t freeHeap = esp_get_free_heap_size();
  if (freeHeap < 6000) {
    Serial.printf("警告：内存不足！可用内存: %u bytes\n", freeHeap);
    // 执行内存回收或安全重启
  }

  // 监控电压状态（假设有readBatteryVoltage函数）
  #ifdef readBatteryVoltage
  float voltage = readBatteryVoltage();
  if (voltage < 3.3) {
    Serial.printf("警告：电压过低！当前电压: %.2f V\n", voltage);
    // 执行安全关机或重启
  }
  #endif

  // 串口输出可用堆内存
  if (print_key) {
    static unsigned long lastHeapPrint = 0;
    if (millis() - lastHeapPrint > 5000) {
      Serial.printf("当前可用堆内存: %u bytes, 最小可用堆内存: %u bytes\n", 
                   freeHeap, ESP.getMinFreeHeap());
      lastHeapPrint = millis();
    }
  }

  // 主循环功能
  if (deviceConnected_g) {
    setConstantColor(0, 0, 0, 255); // LED1红色闪烁5次
  } else {
    setBlinkingColor(0, 0, 0, 255, 250, 5); // LED1红色闪烁5次
  }

  batteryLevel_g = readBatteryStatus(); // 读取电池电量
}